package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xuecheng.api.content.model.dto.CourseBaseDTO;
import com.xuecheng.api.content.model.dto.TeachplanDTO;
import com.xuecheng.api.content.model.dto.TeachplanMediaDTO;
import com.xuecheng.api.content.model.qo.QueryTeachplanMediaModel;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.AuditEnum;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.enums.content.CourseGradeEnum;
import com.xuecheng.common.enums.content.CourseModeEnum;
import com.xuecheng.common.enums.content.TeachPlanEnum;
import com.xuecheng.common.exception.BusinessException;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.content.agent.MediaApiAgent;
import com.xuecheng.content.common.constant.ContentErrorCode;
import com.xuecheng.content.convert.TeachplanConvert;
import com.xuecheng.content.convert.TeachplanMediaConvert;
import com.xuecheng.content.entity.CourseBase;
import com.xuecheng.content.entity.Teachplan;
import com.xuecheng.content.entity.TeachplanMedia;
import com.xuecheng.content.entity.ext.TeachplanNode;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.service.CourseBaseService;
import com.xuecheng.content.service.TeachplanMediaService;
import com.xuecheng.content.service.TeachplanService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 课程计划 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class TeachplanServiceImpl extends ServiceImpl<TeachplanMapper, Teachplan> implements TeachplanService {
    @Autowired
    private CourseBaseService courseBaseService;

    @Autowired
    private TeachplanMediaService teachplanMediaService;

    @Autowired
    private MediaApiAgent mediaApiAgent;

    /*
     *  1.效验是否在本机构
     *  2.查询全部数据
     *      递归生成树节点
     * @param courseBaseId
     * @param companyId
     * @return
     */
    @Override
    public TeachplanDTO queryTree(Long courseBaseId, Long companyId) {
        CourseBaseDTO courseBase = courseBaseService.getCourseBaseById(courseBaseId, companyId);
        List<TeachplanNode> nodes = baseMapper.selectTreeNodesByCourseBaseId(courseBase.getCourseBaseId());
        TeachplanDTO teachplanDTO = null;
        if(nodes!=null && nodes.size()>0){
            TeachplanNode rootNode = nodes.remove(0);
            getTreeNodes(rootNode, nodes);
            teachplanDTO = TeachplanConvert.INSTANCE.node2Dto(rootNode);
        }
        return teachplanDTO;
    }

    /*
     *
     * @param teachplanDTO
     * @param companyId
     * @return
     */
    @Transactional
    @Override
    public TeachplanDTO createOrModifyTeachPlan(TeachplanDTO dto, Long companyId) {
        //判断新增还是修改
        Long teachPlanId = dto.getTeachPlanId();
        if (ObjectUtils.isEmpty(teachPlanId)) {
            return createTeachPlan(dto, companyId);
        } else {
            return modifyTeachPlan(dto, companyId);
        }
    }

    @Override
    public boolean  removeTeachPlan(Long teachPlanId, Long companyId) {
        if(ObjectUtils.isEmpty(teachPlanId)){
            ExceptionCast.cast(ContentErrorCode.E_120401);
        }
        Teachplan teachplan = this.getById(teachPlanId);
        if(ObjectUtils.isEmpty(teachplan)){
            ExceptionCast.cast(ContentErrorCode.E_120401);
        }
        courseBaseService.getCourseBaseById(teachplan.getCourseId(),companyId);

        LambdaQueryWrapper<Teachplan> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(Teachplan::getParentid,teachplan.getId());
        lambdaQueryWrapper.eq(Teachplan::getCourseId,teachplan.getCourseId());
        int count = this.count(lambdaQueryWrapper);
        if(count>0){
            ExceptionCast.cast(ContentErrorCode.E_120416);
        }
        boolean remove = this.removeById(teachPlanId);

        ExceptionCast.cast(!remove,ContentErrorCode.E_120415);
        return true;
    }


    /*
     * 1.判断关键数据
     * 2.判断业务数据
     *      判断课程计划信息
     *          课程计划是否存在
     *          课程计划是否第三级
     *      判断课程信息
     *          课程信息是否存在
     *          课程信息的审核状态
     *          课程信息是否在同一家机构
     *      判断媒资信息
     *          媒资信息是否存在
     *          媒资信息是否审核通过
     *          判断是否是同一家机构
     *
     * 3.课程计划绑定媒资并返回结果
     * @param qo
     * @param companyId
     * @return
     */
    @Override
    public TeachplanMediaDTO associateMedia(QueryTeachplanMediaModel qo, Long companyId) {
        //1.判断关键数据
        Long teachplanId = qo.getTeachplanId();
        Long mediaId = qo.getMediaId();
        if(ObjectUtils.isEmpty(companyId)||ObjectUtils.isEmpty(teachplanId)||ObjectUtils.isEmpty(mediaId)){
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        //判断业务数据
        //判断课程计划信息
        Teachplan teachplan = this.getById(teachplanId);
        ExceptionCast.cast(ObjectUtils.isEmpty(teachplan),ContentErrorCode.E_120013);
        ExceptionCast.cast(!ObjectUtils.nullSafeEquals(TeachPlanEnum.THIRD_LEVEL,teachplan.getGrade()),ContentErrorCode.E_120013);

        //判断课程信息
        LambdaQueryWrapper<CourseBase> courseBaseQuery = Wrappers.lambdaQuery();
        courseBaseQuery.eq(CourseBase::getId,teachplan.getCourseId());
        courseBaseQuery.eq(CourseBase::getCompanyId,companyId);
        CourseBase courseBase = courseBaseService.getOne(courseBaseQuery);
        ExceptionCast.cast(ObjectUtils.isEmpty(courseBase),ContentErrorCode.E_120013);
        ExceptionCast.cast(!ObjectUtils.nullSafeEquals(courseBase.getStatus(),Integer.valueOf(CommonEnum.USING_FLAG.getCode())),ContentErrorCode.E_120013);
        String auditStatus = courseBase.getAuditStatus();
        if(!ObjectUtils.nullSafeEquals(auditStatus, CourseAuditEnum.AUDIT_DISPAST_STATUS.getCode().toString()) &&
                !ObjectUtils.nullSafeEquals(auditStatus, CourseAuditEnum.AUDIT_UNPAST_STATUS.getCode().toString())){
            ExceptionCast.cast(ContentErrorCode.E_120016);
        }
        ExceptionCast.cast(!ObjectUtils.nullSafeEquals(courseBase.getTeachmode(), CourseModeEnum.COURSE_MODE_RECORD_STATUS.getCode()),ContentErrorCode.E_120411);

        //判断媒资信息
        RestResponse<MediaDTO> media4s = mediaApiAgent.getMedia4s(mediaId);
        if(!media4s.isSuccessful()){
            ExceptionCast.castWithCodeAndDesc(media4s.getCode(),media4s.getMsg());
        }
        MediaDTO mediaDTO = media4s.getResult();
        ExceptionCast.cast(!ObjectUtils.nullSafeEquals(mediaDTO.getCompanyId(),companyId),CommonErrorCode.E_403000);
        ExceptionCast.cast(!ObjectUtils.nullSafeEquals(mediaDTO.getAuditStatus(),AuditEnum.AUDIT_PASTED_STATUS.getCode().toString()),CommonErrorCode.E_403000);

        //绑定媒资信息
//        查看媒资信息是否存在
        LambdaQueryWrapper<TeachplanMedia> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(TeachplanMedia::getTeachplanId,teachplanId);
        queryWrapper.eq(TeachplanMedia::getCourseId,courseBase.getId());
        TeachplanMedia po = teachplanMediaService.getOne(queryWrapper);
        if(po!=null){
            po.setMediaId(mediaDTO.getId());
            po.setMediaFilename(mediaDTO.getFilename());
            boolean b = teachplanMediaService.updateById(po);
            if(!b){
                ExceptionCast.cast(ContentErrorCode.E_120411);
            }
            return TeachplanMediaConvert.INSTANCE.entity2dto(po);
        }else{
            TeachplanMedia teachplanMedia = new TeachplanMedia();
            teachplanMedia.setTeachplanId(teachplanId);
            teachplanMedia.setMediaId(mediaId);
            teachplanMedia.setCourseId(courseBase.getId());
            teachplanMedia.setMediaFilename(mediaDTO.getFilename());
            boolean save = teachplanMediaService.save(teachplanMedia);
            if(!save){
                ExceptionCast.cast(ContentErrorCode.E_120411);
            }
            return TeachplanMediaConvert.INSTANCE.entity2dto(po);
        }

    }

    /*
     * 修改
     * @param dto
     * @param companyId
     * @return
     */
    private TeachplanDTO modifyTeachPlan(TeachplanDTO dto, Long companyId) {
        //效验数据
        String pname = dto.getPname();
        if (StringUtil.isBlank(pname)) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }

        CourseBaseDTO courseBase = courseBaseService.getCourseBaseById(dto.getCourseId(), companyId);
        if(ObjectUtils.isEmpty(courseBase)){
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        Long teachplanId = dto.getTeachPlanId();
        Teachplan tp = this.getById(teachplanId);
        if(ObjectUtils.isEmpty(tp)){
            ExceptionCast.cast(ContentErrorCode.E_120402);
        }
        Teachplan po = TeachplanConvert.INSTANCE.dto2entity(dto);
//        po.setParentid(tp.getParentid());
//        po.setGrade(tp.getGrade());
//        po.setOrderby(tp.getOrderby());
//        po.setCourseId(tp.getCourseId());
//        boolean result = this.updateById(po);
        // 信息修改的内容：pname 、 is_preview、media_type、starttime、endtime

        LambdaUpdateWrapper<Teachplan> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Teachplan::getPname, dto.getPname());
        updateWrapper.set(Teachplan::getIsPreview, dto.getIsPreview());
        updateWrapper.set(Teachplan::getMediaType, dto.getMediaType());
        updateWrapper.set(Teachplan::getStartTime, dto.getStartTime());
        updateWrapper.set(Teachplan::getEndTime, dto.getEndTime());

        updateWrapper.eq(Teachplan::getId, dto.getTeachPlanId());

        boolean result = this.update(updateWrapper);
        //  4.修改数据并判断修改后的结果

        ExceptionCast.cast(!result,ContentErrorCode.E_120407);
        //  5.返回数据内容dto
        TeachplanDTO resultDTO = TeachplanConvert.INSTANCE.entity2Dto(po);
        return resultDTO;
    }

    /*
     * 新增课程计划
     * 1.判断关键数据
     * 2.判断业务数据
     * 3.判断第几层级
     * @param dto
     * @param companyId
     * @return
     */
    private TeachplanDTO createTeachPlan(TeachplanDTO dto, Long companyId) {
        String pname = dto.getPname();
        if (StringUtil.isBlank(pname)) {
            ExceptionCast.cast(ContentErrorCode.E_120004);
        }
        CourseBaseDTO courseBase = courseBaseService.getCourseBaseById(dto.getCourseId(), companyId);
        if(ObjectUtils.isEmpty(courseBase)){
            ExceptionCast.cast(ContentErrorCode.E_120013);
        }
        if(ObjectUtils.isEmpty(dto.getParentid())){//第二级
            //判断根节点是否存在
            LambdaQueryWrapper<Teachplan> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(Teachplan::getCourseId,dto.getCourseId());
            queryWrapper.eq(Teachplan::getParentid, TeachPlanEnum.FIRST_PARENTID_FLAG);
            queryWrapper.eq(Teachplan::getGrade,TeachPlanEnum.FIRST_LEVEL);
            Teachplan rootNode = this.getOne(queryWrapper);
            if(ObjectUtils.isEmpty(rootNode)){//空的创建
                rootNode = new Teachplan();
                rootNode.setPname(courseBase.getName());
                rootNode.setParentid(new Long(TeachPlanEnum.FIRST_PARENTID_FLAG.toString()));
                rootNode.setGrade(TeachPlanEnum.FIRST_LEVEL);
                rootNode.setDescription(courseBase.getDescription());
                rootNode.setOrderby(TeachPlanEnum.FIRST_LEVEL);
                rootNode.setCourseId(courseBase.getCourseBaseId());
                boolean result = this.save(rootNode);
                ExceptionCast.cast(!result,ContentErrorCode.E_120407);
            }
            Teachplan teachplan = TeachplanConvert.INSTANCE.dto2entity(dto);
            teachplan.setGrade(TeachPlanEnum.SECEND_LEVEL);
            teachplan.setParentid(rootNode.getId());
            boolean saveResult = this.save(teachplan);
            ExceptionCast.cast(!saveResult,ContentErrorCode.E_120407);
            return TeachplanConvert.INSTANCE.entity2Dto(teachplan);

        }else{//第三级
            LambdaQueryWrapper<Teachplan> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(Teachplan::getCourseId,dto.getCourseId());
            queryWrapper.eq(Teachplan::getId, dto.getParentid());
//            queryWrapper.eq(Teachplan::getGrade,dto.getGrade()-1);
            Teachplan secendNode = this.getOne(queryWrapper);
            if(ObjectUtils.isEmpty(secendNode)){
                ExceptionCast.cast(ContentErrorCode.E_120408);
            }
            Teachplan teachplan = TeachplanConvert.INSTANCE.dto2entity(dto);
            teachplan.setGrade(TeachPlanEnum.THIRD_LEVEL);
            teachplan.setParentid(secendNode.getId());
            int count = this.count();
            teachplan.setOrderby(count+1);
            boolean saveResult = this.save(teachplan);
            ExceptionCast.cast(!saveResult,ContentErrorCode.E_120407);
            return TeachplanConvert.INSTANCE.entity2Dto(teachplan);
        }
    }


    private void getTreeNodes(TeachplanNode rootNode, List<TeachplanNode> nodes) {
        //判断子节点集合是否为空
        List<TeachplanNode> childrenNodes = rootNode.getChildrenNodes();
        if (CollectionUtils.isEmpty(childrenNodes)) {
            childrenNodes = new ArrayList<>();
            rootNode.setChildrenNodes(childrenNodes);
        }
        for (TeachplanNode node : nodes) {
            //判断子节点的parentid是不是父节点的id
            if (ObjectUtils.nullSafeEquals(node.getParentid(), rootNode.getId())) {
                childrenNodes.add(node);
                if(!node.getGrade().equals(TeachPlanEnum.THIRD_LEVEL)){
                    getTreeNodes(node, nodes);
                }else{
                    LambdaQueryWrapper<TeachplanMedia> queryWrapper = Wrappers.lambdaQuery();
                    queryWrapper.eq(TeachplanMedia::getTeachplanId,node.getId());
                    queryWrapper.eq(TeachplanMedia::getCourseId,node.getCourseId());
                    TeachplanMedia teachplanMedia = teachplanMediaService.getOne(queryWrapper);
                    node.setTeachplanMedia(teachplanMedia);

                }
            }
        }
    }
}
